﻿/************************************************************************************
* Copyright (c) 2019 All Rights Reserved.
*命名空间：Merge.Model
*文件名： ClassifyEngine
*创建人： Liebeskind
*创建时间：2019/6/20 17:10:27
*描述
*=====================================================================
*修改标记
*修改时间：2019/6/20 17:10:27
*修改人：Liebeskind
*描述：类的模型和类的驱动
*      约定：
*      特征向量=类型
*      特征=特征向量的基
*      特征值=特征向量的基向量的值
*      取值范围和值域=值域
*      矩阵含义：( L P K R )T
************************************************************************************/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Commonality.DAL.WZS_SFCS;
using MathNet.Numerics.LinearAlgebra.Double;

namespace Merge.Model.Classify
{
    /// <summary>
    /// 类模型
    /// </summary>
    public class ClassModel
    {
        /// <summary>
        /// 类的特征向量
        /// </summary>
        public CEigenvector Eigenvector { get; set; }
        public ClassModel()
        {

        }
        /// <summary>
        /// 构造类的特征向量
        /// </summary>
        /// <param name="LINEi">线别</param>
        /// <param name="PN">料号</param>
        /// <param name="PNcm">PN编码(可扩充集动态标记)</param>
        /// <param name="KCAndBF">空格KC和butterfly组合值</param>
        /// <param name="Remark">产品类型</param>
        public ClassModel(LINE LINEi, string PN, int PNcm, KCAndBF KCAndBF, Remark Remark)
        {
            this.Eigenvector = new CEigenvector(LINEi, PN, KCAndBF, Remark, DenseMatrix.OfArray(new[,] { { (double)LINEi }, { (double)PNcm }, { (double)KCAndBF }, { (double)Remark } }));

            StringEigenvector = (int)LINEi + "," + PNcm + "," + (int)KCAndBF + "," + (int)Remark;
        }
        /// <summary>
        /// 特征向量字符格式
        /// </summary>
        public string StringEigenvector { get; set; }
    }

    public class ClassifyEngine
    {
        /// <summary>
        /// **类型(特征向量)的集合(包含所有的类型，非某一类实例的集合)**
        /// </summary>
        public List<ClassModel> ClassModels;
        /// <summary>
        /// 类的数量，共有多少个特征向量
        /// </summary>
        public int ClassModelsCount { get; set; }

        #region 特征值域的变量
        /// <summary>
        /// 是否考虑产品类型方向上的投影(若考虑，使值域内所有值都是特征值，暂时不考虑特征值值域为值域真子集的方式，故使用布尔量表记)
        /// </summary>
        public bool ProjectionBasisRemarkFlag { get; set; }
        /// <summary>
        /// Remark特征值域
        /// </summary>
        private List<Remark> ProjectionBasisRemark { get; set; }
        /// <summary>
        /// 线别方向上的特征值值域(若不考虑线别方向上投影则特征值域为空集，如果考量则特征值域为此数域上的真子集，所以必须列举出具体值)
        /// </summary>
        public List<LINE> ProjectionBasisLINE { get; set; }
        /// <summary>
        /// 料号的特征值域
        /// </summary>
        public List<string> ProjectionBasisPN { get; set; }
        /// <summary>
        /// KC+BF特征值域
        /// </summary>
        public List<KCAndBF> ProjectionBasisKCAndBF { get; set; }
        #endregion

        /// <summary>
        /// 实例一个分类器
        /// </summary>
        public ClassifyEngine()
        {
            ClassModels = new List<ClassModel>();
            ProjectionBasisLINE = new List<LINE>();
            ProjectionBasisPN = new List<string>();
            ProjectionBasisKCAndBF = new List<KCAndBF>();
            ProjectionBasisRemark = new List<Remark>();


            ProjectionBasisRemarkFlag = false;
            ProjectionBasisLINE.Add(LINE.ZERO);                     //重要的:必须存在不含线别特征的类型
            ProjectionBasisPN.Add("Liebeskind Written in 2019 ^_^ ");    //避免NULL
            ConstructionClassModelFunc();                              //构造初始的基本分类，事实上到此还没有有效的PN特征值
        }
        /// <summary>
        /// 构造新类型
        /// 构造新类的前提就是扩充特征向量的基矢量的值域
        /// 特别的:包括LINE、KCBF、Remark在内的三项特征是有限集，而PN在广义上是无限集，所以新类型的产生驱动源是新的PN
        /// </summary>
        private void ConstructionClassModelFunc()
        {
            ClassModels.Clear();

            #region Remark特征值域的从新选择
            if (ProjectionBasisRemarkFlag)
            {
                ProjectionBasisRemark.Clear();
                foreach (var item in Enum.GetValues(typeof(Remark)))
                {
                    if ((Remark)item != Remark.ZERO)
                    {
                        ProjectionBasisRemark.Add((Remark)item);        //选定特征值域:考虑Remark特征，特征值域选定非空全集
                    }
                }
            }
            else
            {
                ProjectionBasisRemark.Clear();
                ProjectionBasisRemark.Add(Remark.ZERO);        //选定特征值域:忽略Remark特征，特征值域选定空集
            }
            #endregion
            #region KC+BF特征值域的从新选择
            ProjectionBasisKCAndBF.Clear();
            foreach (var item in Enum.GetValues(typeof(KCAndBF)))
            {
                if ((KCAndBF)item != KCAndBF.ZERO)
                {
                    ProjectionBasisKCAndBF.Add((KCAndBF)item);        //选定特征值域:KC+BF特征必须考虑，特征值域为非空全集
                }
            }
            #endregion
            #region PN特征集合去重
            List<string> OleListPN = ProjectionBasisPN;
            List<string> NewListPN = new List<string>();
            Hashtable hashPN = new Hashtable();
            foreach (var item in OleListPN)
            {
                if (!hashPN.ContainsKey(item))
                {
                    hashPN.Add(item, item);
                    NewListPN.Add(item);
                }
            }
            ProjectionBasisPN.Clear();
            ProjectionBasisPN = NewListPN;
            #endregion
            #region LINE特征去重
            List<LINE> OleListLINE = ProjectionBasisLINE;
            List<LINE> NewListLINE = new List<LINE>();
            Hashtable hashLINE = new Hashtable();
            foreach (var item in OleListLINE)
            {
                if (!hashLINE.ContainsKey(item))
                {
                    hashLINE.Add(item, item);
                    NewListLINE.Add(item);
                }
            }
            ProjectionBasisLINE.Clear();
            ProjectionBasisLINE = NewListLINE;
            #endregion
            foreach (var item_LINEi in ProjectionBasisLINE)
            {
                foreach (var item_PNi in ProjectionBasisPN)
                {
                    foreach (var item_KCAndBF in ProjectionBasisKCAndBF)
                    {
                        foreach (var item_Remarki in ProjectionBasisRemark)
                        {
                            ClassModels.Add(new ClassModel(item_LINEi, item_PNi, ProjectionBasisPN.IndexOf(item_PNi), item_KCAndBF, item_Remarki));   //刷新特征向量集合
                        }
                    }
                }
            }
            ClassModelsCount = ClassModels.Count;


        }


        /// <summary>
        /// 添加一个LINE特征的值（增加一个线别分支）
        /// 面向外部的有限可变集合
        /// </summary>
        /// <param name="LINEi"></param>
        public void ConstructionClassModelFunc_AddLINEi(LINE LINEi)
        {
            this.ProjectionBasisLINE.Add(LINEi);
            ConstructionClassModelFunc();
        }
        /// <summary>
        /// 移除一个LINE特征的值（删除一个线别分支）
        /// </summary>
        /// <param name="LINEi"></param>
        public void ConstructionClassModelFunc_RemoveLINEi(LINE LINEi)
        {
            this.ProjectionBasisLINE.Remove(LINEi);
            ConstructionClassModelFunc();
        }


        /// <summary>
        /// 重要的：从陌生实例datalist中提取类型等特征，并进行认证识别构造新类:连接SFCS与分类器的入口
        /// 物理上是进入分类区前进行识别认证，并存入数据库
        /// </summary>
        /// <param name="productCellData"></param>
        /// <param name="classModel"></param>
        public void NewEigenvectorExtract(ProductCellData productCellData,ref ClassModel classModel)
        {
            //TODU:未明确datainfo中线别字段,未明确KC+BF字段
            LINE line = LINE.TB1_1FT_01;
            string pn = productCellData.usnInfo[1];
            KCAndBF kCAndBF = KCAndBF.One;
            Remark remark = Remark.ZERO;

            //非标记线别都归为通用线别
            if (ProjectionBasisLINE.IndexOf(line) == -1)
            {
                //属于未标记的通用线别
                line = LINE.ZERO;
            }
            //新旧PN分类
            if (ProjectionBasisPN.IndexOf(pn) == -1)
            {
                //新PN
                //classModel = new ClassModel(line, pn, -1, kCAndBF, remark);         //特征向量中PN值，-1表示未识别的新PN
                classModel = new ClassModel(line, pn, -1, kCAndBF, remark);         //特征向量中PN值，-1表示未识别的新PN
            }
            else
            {
                //旧PN
                classModel = new ClassModel(line, pn, ProjectionBasisPN.IndexOf(pn), kCAndBF, remark);
            }

            ClassLivingAdjust(ref classModel);          //最终认证被纳入类型集合或产生新类
        }

        //public void
        #region 私有
        /// <summary>
        /// 0
        /// </summary>
        private DenseMatrix Zero11 = new DenseMatrix(1,1,new double[] { 0});
        /// <summary>
        /// 0000
        /// 0000
        /// 0000
        /// 0000
        /// </summary>
        private DenseMatrix Zero44 = new DenseMatrix(4, 4,new double[] { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0});

        private void RemoveRepetitive(ref List<string> list)
        {
            List<string> OleList = list;
            List<string> NewList = new List<string>();
            Hashtable hash = new Hashtable();
            foreach (var item in OleList)
            {
                if (!hash.ContainsKey(item))
                {
                    hash.Add(item, item);
                    NewList.Add(item);
                }
            }
            list = OleList;
        }


        /// <summary>
        /// 狭义上，构造新类的驱动
        /// </summary>
        /// <param name="PN"></param>
        private void ConstructionClassModelFunc_AddPNi(string PN)
        {
            this.ProjectionBasisPN.Add(PN);
            ConstructionClassModelFunc();
        }

        /// <summary>
        /// 重要的:对"陌生"实例进行识别("标记线别"和"通用线别"区分、新类型识别并构造类型、)
        /// </summary>
        /// <param name="newLiving"></param>
        private void ClassLivingAdjust(ref ClassModel newLiving)
        {
            List<DenseMatrix> Differ = new List<DenseMatrix>();
            foreach (var item in ClassModels)
            {
                //Differ.Add(item.CEigenvector.MEigenvector - newLiving.CEigenvector.MEigenvector);
                Differ.Add(item.Eigenvector.MEigenvector - newLiving.Eigenvector.MEigenvector);
            }

            //
            #region 属于旧有类别
            foreach (var item in Differ)
            {
                if (item.SubMatrix(0, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(1, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(2, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(3, 1, 0, 1).Equals(Zero11))
                {
                    //属于被标记的线别,且非新PN:属于存在旧同类
                    return;
                }
            }
            #endregion

            #region 属于未被标记的线别
            foreach (var item in Differ)
            {
                if ( !item.SubMatrix(0, 1, 0, 1).Equals(Zero11) &&
                     item.SubMatrix(1, 1, 0, 1).Equals(Zero11) &&
                     item.SubMatrix(2, 1, 0, 1).Equals(Zero11) &&
                     item.SubMatrix(3, 1, 0, 1).Equals(Zero11))
                {
                    ////归零到通用线别:此实例的线别值非0也非标记值，需要归0，视为通用线别，且非新PN
                    //newLiving.CEigenvector.LINEi = LINE.ZERO;
                    ////newLiving.CEigenvector.MEigenvector.Detail[0, 0] = 0;
                    //newLiving.CEigenvector.MEigenvector.ClearSubMatrix(0, 1, 0, 1);

                    //归零到通用线别:此实例的线别值非0也非标记值，需要归0，视为通用线别，且非新PN
                    newLiving.Eigenvector.LINEi = LINE.ZERO;
                    //newLiving.CEigenvector.MEigenvector.Detail[0, 0] = 0;
                    newLiving.Eigenvector.MEigenvector.ClearSubMatrix(0, 1, 0, 1);
                    return;
                }
            }
            #endregion

            #region 新PN,属于被标记的线别，但是是新PN
            foreach (var item in Differ)
            {
                if (item.SubMatrix(0, 1, 0, 1).Equals(Zero11) &&
                    !item.SubMatrix(1, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(2, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(3, 1, 0, 1).Equals(Zero11))
                {
                    ////新PN,属于被标记的线别，但是是新PN
                    //DenseMatrix PNi = new DenseMatrix(4, 1, new double[] { 0, ProjectionBasisPN.Count + 1, 0, 0 });
                    //newLiving.CEigenvector.MEigenvector = newLiving.CEigenvector.MEigenvector + PNi;
                    //newLiving.StringEigenvector = "0," + ProjectionBasisPN.Count + "," + newLiving.CEigenvector.MEigenvector.SubMatrix(2, 1, 0, 1).Determinant() + "," + newLiving.CEigenvector.MEigenvector.SubMatrix(3, 1, 0, 1).Determinant();
                    //ConstructionClassModelFunc_AddPNi(newLiving.CEigenvector.PN);   //构造新类

                    //新PN,属于被标记的线别，但是是新PN
                    DenseMatrix PNi = new DenseMatrix(4, 1, new double[] { 0, ProjectionBasisPN.Count + 1, 0, 0 });
                    newLiving.Eigenvector.MEigenvector = newLiving.Eigenvector.MEigenvector + PNi;
                    newLiving.StringEigenvector = "0," + ProjectionBasisPN.Count + "," + newLiving.Eigenvector.MEigenvector.SubMatrix(2, 1, 0, 1).Determinant() + "," + newLiving.Eigenvector.MEigenvector.SubMatrix(3, 1, 0, 1).Determinant();
                    ConstructionClassModelFunc_AddPNi(newLiving.Eigenvector.PN);   //构造新类
                    return;
                }
            }
            #endregion

            #region 新PN且非标记线别
            foreach (var item in Differ)
            {

                if (!item.SubMatrix(0, 1, 0, 1).Equals(Zero11)&&
                    !item.SubMatrix(1, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(2, 1, 0, 1).Equals(Zero11) &&
                    item.SubMatrix(3, 1, 0, 1).Equals(Zero11))
                    {
                        ////新PN，且需要归零到通用线别:此实例的线别值非0也非标记值，需要归0，视为通用线别，且是新PN
                        //newLiving.CEigenvector.LINEi = LINE.ZERO;
                        //newLiving.CEigenvector.MEigenvector.ClearSubMatrix(0, 1, 0, 1);
                        //DenseMatrix PNi = new DenseMatrix(4, 1, new double[] { 0, ProjectionBasisPN.Count +1,0,0});
                        //newLiving.CEigenvector.MEigenvector = newLiving.CEigenvector.MEigenvector + PNi;
                        //newLiving.StringEigenvector = "0," + ProjectionBasisPN.Count + "," + newLiving.CEigenvector.MEigenvector.SubMatrix(2, 1, 0, 1).Determinant() + "," + newLiving.CEigenvector.MEigenvector.SubMatrix(3, 1, 0, 1).Determinant();
                        //ConstructionClassModelFunc_AddPNi(newLiving.CEigenvector.PN);   //构造新类

                    //新PN，且需要归零到通用线别:此实例的线别值非0也非标记值，需要归0，视为通用线别，且是新PN
                    newLiving.Eigenvector.LINEi = LINE.ZERO;
                    newLiving.Eigenvector.MEigenvector.ClearSubMatrix(0, 1, 0, 1);
                    DenseMatrix PNi = new DenseMatrix(4, 1, new double[] { 0, ProjectionBasisPN.Count + 1, 0, 0 });
                    newLiving.Eigenvector.MEigenvector = newLiving.Eigenvector.MEigenvector + PNi;
                    newLiving.StringEigenvector = "0," + ProjectionBasisPN.Count + "," + newLiving.Eigenvector.MEigenvector.SubMatrix(2, 1, 0, 1).Determinant() + "," + newLiving.Eigenvector.MEigenvector.SubMatrix(3, 1, 0, 1).Determinant();
                    ConstructionClassModelFunc_AddPNi(newLiving.Eigenvector.PN);   //构造新类
                    return;
                    }
            }
            #endregion
            
        }
        #endregion
    }
}
